use std::str::FromStr;

use sea_orm::{
    ActiveModelTrait, ColumnTrait, EntityTrait, NotSet, PaginatorTrait, QueryFilter, QueryOrder,
};
use sea_orm::ActiveValue::Set;

use common::ctx::get_db;
use common::error::MyError;
use common::page::{BasePage, PageResult};
use entity::prelude::SysDict;
use entity::sys_dict;
use model::dict::{CreateDict, DictPage};

use crate::manager::base::BaseManager;
use crate::manager::dict_group::DictGroupManager;

pub struct DictManager {}

impl BaseManager<i64, sys_dict::Model, DictPage, CreateDict, sys_dict::Model> for DictManager {
    async fn list() -> Result<Vec<sys_dict::Model>, MyError> {
        let list = SysDict::find().all(&*get_db()?).await?;
        Ok(list)
    }

    async fn page(page: DictPage) -> Result<PageResult<sys_dict::Model>, MyError> {
        let mut find = SysDict::find();
        //排序
        if let Some(sorter) = page.get_order() {
            let field = sys_dict::Column::from_str(sorter.field.as_str()).or_else(|e| {
                Err(MyError::DBError(format!(
                    "获取排序字段失败：{}",
                    e.to_string()
                )))
            })?;
            find = find.order_by(field, sorter.order());
        }

        if let Some(group_id) = page.group_id {
            find = find.filter(sys_dict::Column::GroupId.eq(group_id))
        }
        if let Some(parent_id) = page.parent_id {
            find = find.filter(sys_dict::Column::ParentId.eq(parent_id))
        }
        if let Some(ref name) = page.name {
            find = find.filter(sys_dict::Column::Name.like(format!("%{}%", name)))
        }
        if let Some(ref code) = page.code {
            find = find.filter(sys_dict::Column::Code.eq(code))
        }
        if let Some(default) = page.default {
            find = find.filter(sys_dict::Column::Default.eq(default))
        }
        if let Some(ref dict_desc) = page.dict_desc {
            find = find.filter(sys_dict::Column::DictDesc.like(format!("%{}%", dict_desc)))
        }

        //校验并获取分页数据
        let page_data = page.check_page_data();
        //每页大小
        let db_conn = &*get_db()?;
        let paginator = find.paginate(db_conn, page_data.page_size);

        //执行分页查询
        let record = paginator.fetch_page(page_data.page - 1).await?;
        //总条数
        let total = paginator.num_items().await?;
        //返回分页结果
        Ok(PageResult {
            page: page_data.page,
            page_size: page_data.page_size,
            total,
            record,
        })
    }

    async fn info(id: i64) -> Result<Option<sys_dict::Model>, MyError> {
        Ok(SysDict::find_by_id(id).one(&*get_db()?).await?)
    }

    async fn add(form: CreateDict) -> Result<i64, MyError> {
        let name = form
            .name
            .ok_or(MyError::ServerError("名称不能为空".to_string()))?;
        let code = form
            .code
            .ok_or(MyError::ServerError("编码不能为空".to_string()))?;
        let parent_id = check_parent_id(&form.parent_id).await?;
        let group_id = form
            .group_id
            .ok_or(MyError::ServerError("group_id不能为空".to_string()))?;
        check_dict_code(group_id, code.clone()).await?;
        let group = DictGroupManager::info(group_id).await?;
        if let Some(group) = group {
            let model = sys_dict::ActiveModel {
                id: NotSet,
                parent_id: Set(parent_id),
                name: Set(Some(name)),
                code: Set(Some(code)),
                value: Set(form.value),
                level: Set(Some(1)),
                group_id: Set(Some(group_id)),
                group_code: Set(Some(group.group_code.unwrap())),
                default: Set(form.default),
                dict_desc: Set(form.dict_desc),
            }
            .insert(&*get_db()?)
            .await?;
            Ok(model.id)
        } else {
            Err(MyError::ServerError("分组不存在".to_string()))
        }
    }

    async fn update(form: sys_dict::Model) -> Result<i64, MyError> {
        let entity =
            SysDict::find_by_id(form.id)
                .one(&*get_db()?)
                .await?
                .ok_or(MyError::ServerError(format!(
                    "user [{:?}] does not exist",
                    form.id
                )))?;
        let mut entity: sys_dict::ActiveModel = entity.into();
        if form.name.is_some() {
            entity.name = Set(form.name);
        }
        if form.code.is_some() {
            check_dict_code_and_id_no_in(
                entity.group_id.clone().unwrap().unwrap(),
                form.id,
                form.code.clone().unwrap(),
            )
            .await?;
            entity.code = Set(form.code);
        }
        if form.parent_id.is_some() {
            entity.parent_id = Set(form.parent_id);
        }
        let result = entity.update(&*get_db()?).await?;
        Ok(result.id)
    }

    async fn delete(id: i64) -> Result<bool, MyError> {
        let res = SysDict::delete_by_id(id).exec(&*get_db()?).await?;
        Ok(res.rows_affected == 1)
    }
}

impl DictManager {
    pub async fn get_by_group_id(group_id: i64) -> Result<Vec<sys_dict::Model>, MyError> {
        let list = SysDict::find()
            .filter(sys_dict::Column::GroupId.eq(group_id))
            .all(&*get_db()?)
            .await?;
        Ok(list)
    }
}

async fn check_parent_id(parent_id: &Option<i64>) -> Result<Option<i64>, MyError> {
    if !parent_id.is_some() || parent_id.unwrap() == 0 {
        Ok(Some(0))
    } else {
        let parent = DictManager::info(parent_id.clone().unwrap()).await?;
        match parent {
            None => Err(MyError::ServerError("父级字典不存在".to_string())),
            Some(_) => Ok(parent_id.clone()),
        }
    }
}
async fn check_dict_code(group_id: i64, dict_code: String) -> Result<(), MyError> {
    let list = SysDict::find()
        .filter(sys_dict::Column::GroupId.eq(group_id))
        .filter(sys_dict::Column::Code.eq(dict_code))
        .all(&*get_db()?)
        .await?;
    if !list.is_empty() {
        Err(MyError::ServerError("字典编码已存在".to_string()))
    } else {
        Ok(())
    }
}
async fn check_dict_code_and_id_no_in(
    group_id: i64,
    id: i64,
    dict_code: String,
) -> Result<(), MyError> {
    let list = SysDict::find()
        .filter(sys_dict::Column::Id.ne(id))
        .filter(sys_dict::Column::GroupId.eq(group_id))
        .filter(sys_dict::Column::Code.eq(dict_code))
        .all(&*get_db()?)
        .await?;
    if !list.is_empty() {
        Err(MyError::ServerError("字典编码已存在".to_string()))
    } else {
        Ok(())
    }
}
